package org.fuys.coder.domain.substance.service.operation.impl;

import lombok.extern.slf4j.Slf4j;
import org.fuys.coder.infrastructure.model.dto.SubstanceDataStatusDTO;
import org.fuys.coder.domain.config.service.impl.CoderAuditConfig;
import org.fuys.coder.common.constants.ResultMessageConstants;
import org.fuys.coder.common.exception.BusinessException;
import org.fuys.coder.common.exception.handler.NeedCallBackException;
import org.fuys.coder.domain.audit.service.publisher.AsyncAuditEventPublisher;
import org.fuys.coder.domain.auth.model.vo.token.TokenTypeVO;
import org.fuys.coder.domain.auth.service.vertify.token.ITrustTokenService;
import org.fuys.coder.domain.model.service.IUserModelService;
import org.fuys.coder.domain.substance.model.event.SubstanceReviewEvent;
import org.fuys.coder.domain.substance.model.req.operation.SubstanceDataStatusSelectReq;
import org.fuys.coder.domain.substance.model.req.operation.SubstanceOperationReq;
import org.fuys.coder.domain.substance.model.vo.SubstanceDataStatusVO;
import org.fuys.coder.domain.substance.model.vo.SubstanceOperationTypeVO;
import org.fuys.coder.domain.substance.repository.ISubstanceOperationRepository;
import org.fuys.coder.domain.substance.repository.ISubstanceRepository;
import org.fuys.coder.domain.substance.service.operation.ISubstanceOperationService;
import org.fuys.coder.domain.user.model.vo.repo.UserStatusTypeVO;
import org.fuys.coder.domain.user.service.repo.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.substance.service.operation.impl
 * @className: SubstanceOperationServiceImpl
 * @author: WangJing
 * @description: 内容操作实现类
 * @date: 2024/7/13 11:18
 * @version: 1.0
 */
@Service
@Slf4j
public class SubstanceOperationServiceImpl implements ISubstanceOperationService {

    @Resource
    private ISubstanceRepository substanceRepository;

    @Resource
    private ISubstanceOperationRepository substanceOperationRepository;

    @Resource
    private IUserService userService;

    @Resource
    private IUserModelService userModelService;

    @Resource
    private CoderAuditConfig coderAuditConfig;

    @Resource
    private AsyncAuditEventPublisher asyncAuditEventPublisher;

    @Resource
    private ITrustTokenService tokenService;

    @Override
    @Transactional(rollbackFor = NeedCallBackException.class)
    public boolean thumbSubstance(SubstanceOperationReq req) {
        //检查操作类型 防止恶意攻击 下面意义相同
        if(!req.getOperationType().equals(SubstanceOperationTypeVO.THUMB.getIdx())){
            throw new BusinessException(ResultMessageConstants.ILLEGAL_OPERATION);
        }
        if (!tokenService.checkToken(req.getUserId(),req.getSubstanceId(), TokenTypeVO.SUBSTANCE_THUMB,req.getToken())) {
            throw new BusinessException(ResultMessageConstants.ILLEGAL_OPERATION);
        }
        final Integer status = checkUser(req);
        if(ObjectUtils.isEmpty(status)){
            throw new BusinessException(ResultMessageConstants.UNTRUSTED_USERS);
        }
        //点赞服务 由于涉及多个数据库操作 启用事务 下面意义相同
        boolean flag=substanceOperationRepository.thumbSubstance(req.getSubstanceId(), req.getUserId());
        substanceRepository.thumbSubstance(req.getSubstanceId(),flag);
        updateModel(status,req);
        return flag;
    }

    @Override
    @Transactional(rollbackFor = NeedCallBackException.class)
    public boolean favoritesSubstance(SubstanceOperationReq req) {
        if(!req.getOperationType().equals(SubstanceOperationTypeVO.FAVORITES.getIdx())){
            throw new BusinessException(ResultMessageConstants.ILLEGAL_OPERATION);
        }
        if (!tokenService.checkToken(req.getUserId(),req.getSubstanceId(), TokenTypeVO.SUBSTANCE_FAVORITES,req.getToken())) {
            throw new BusinessException(ResultMessageConstants.ILLEGAL_OPERATION);
        }
        final Integer status = checkUser(req);
        if(ObjectUtils.isEmpty(status)){
            throw new BusinessException(ResultMessageConstants.UNTRUSTED_USERS);
        }
        boolean flag=substanceOperationRepository.favoriteSubstance(req.getSubstanceId(),req.getFavId(),req.getUserId());
        substanceRepository.favoritesSubstance(req.getSubstanceId(),flag);
        updateModel(status,req);
        return flag;
    }

    private Integer checkUser(SubstanceOperationReq req) {
        final Integer userId = req.getUserId();
        final Integer userStatus = userService.getUserStatus(userId);
        if(!userStatus.equals(UserStatusTypeVO.USER_STATUS_NORMAL)){
            //是注销或者封禁的用户 提示没有操作权限
            return null;
        }
        return userStatus;
    }

    private void updateModel(Integer status,SubstanceOperationReq req){
        if(status.equals(UserStatusTypeVO.USER_STATUS_VIP)){
            //是vip用户 进行特殊的推荐模式
            userModelService.addVipUserWeight(req);
        }else{
            //否则进行普通的推荐模式
            userModelService.addCommonUserWeight(req);
        }
    }

    @Override
    @Transactional(rollbackFor = NeedCallBackException.class)
    public void reportSubstance(SubstanceOperationReq req) {
        if(!req.getOperationType().equals(SubstanceOperationTypeVO.FAVORITES.getIdx())){
            throw new BusinessException(ResultMessageConstants.ILLEGAL_OPERATION);
        }
        Long count=substanceOperationRepository.reportSubstance(req);
        if(count>=coderAuditConfig.getReportCount()){
            //改成发送事件的形式 提升用户体验 此事件将被 substance领域的 service.repo 包实现类接收并处理
            //大概逻辑是通过在那边进行获取信息 然后封装需要人工审核的内容
            publishReviewEvent(req);
        }
    }

    @Override
    public SubstanceDataStatusVO selectSubstanceDataStatus(SubstanceDataStatusSelectReq req) {
        try {
            final SubstanceDataStatusDTO substanceDataStatus = substanceRepository.getSubstanceDataStatus(req);
            if(ObjectUtils.isEmpty(substanceDataStatus)){
                final SubstanceDataStatusVO vo = new SubstanceDataStatusVO();
                vo.setFavStatus(false);
                vo.setThumbStatus(false);
                return vo;
            }
            SubstanceDataStatusVO statusVO=new SubstanceDataStatusVO();
            if(!ObjectUtils.isEmpty(substanceDataStatus.getId())){
                statusVO.setThumbStatus(true);
            }
            if(!ObjectUtils.isEmpty(substanceDataStatus.getFavId())){
                statusVO.setFavId(statusVO.getFavId());
                statusVO.setFavStatus(true);
            }
            return statusVO;
        } catch (Exception e) {
            log.error(e.getMessage());
            final SubstanceDataStatusVO vo = new SubstanceDataStatusVO();
            vo.setFavStatus(false);
            vo.setThumbStatus(false);
            return vo;
        }
    }

    private void publishReviewEvent(SubstanceOperationReq req){
        //todo 可能再添加一个事件处理器
        SubstanceReviewEvent reviewEvent=new SubstanceReviewEvent(this);
        reviewEvent.setSubstanceId(req.getSubstanceId());
        reviewEvent.setUserId(req.getUserId());
        reviewEvent.setMsg(req.getMsg());
        asyncAuditEventPublisher.publishSubstanceReviewEvent(reviewEvent);
    }
}
